基于逻辑回归的垃圾邮件过滤

您所在的位置:网站首页 anaconda navigator一直在加载 基于逻辑回归的垃圾邮件过滤

基于逻辑回归的垃圾邮件过滤

2023-04-11 21:01| 来源: 网络整理| 查看: 265

打开分享的文件发现里面还有英文,就不用他的了。

分词时import jieba出错了,显示没有jieba这个模块:

 

由于是头天的晚上出现的这个错误,在网上搜索了一下,发现可以下载jieba库,于是也我打算这样做,但是刚好电脑没电了,于是就没弄。

第二天起来就又搜索了一下这个问题,看了此博主的博客 在jupyter安装jieba出错ModuleNotFoundError: No module named ‘jieba‘的解决办法-CSDN博客 提到的方法5:

 于是我发现这个方法我在头天晚上就试过了,但是出错了

 

 但是我又按照它的提示,通过python -m pip install --upgrade pip升级pip,但是又出错了

 这里虽然告诉我了错误原因,但我并没有去百度这个错误了。

而是去看没有jieba库的解决办法了,又看到这个博主 python3安装jieba成功,但是导入仍然错误 - 简书 (jianshu.com)

 

 于是我也就按照他输入了!pip3 install jieba,

 提示有jieba库,不过它既然有这个库为什么会提示我这个错,到现在我已经忘记我为什么会出现这个错误了,好像自己突然就行了。

不过至此我又发现一个问题就是对一封邮件分完词后,会出现把空格也当成词分进去了:

 于是我好奇为什么会这样呢,往上看代码发现,提取的邮件正文内容中并没有把空格全部去:

 于是分词的时候就出现错误了。

现在开始想解决办法,想到我之前看到的一篇文章里有提到他是如何去空格的,看了一下:

 把空格去掉是这种方式,但是又无法下手,于是去chatGPT搜索了一下这个语句:[re.sub('\s+', '', k) for k in mailContent_list]的作用,解释如下:

 发现这个语句的作用是把多个空格替换为单个空格,这跟我去掉所有空格的理念不符啊,于是再结合另一个博主提到的replace(" ",""),所以我想到

[re.sub('\s+', ' ', k) for k in mailContent_list]中' '的这个替换为'':

 发现就把多余的空格去掉了,好耶nice!

但是在操作中我以为改了结果没改,然后又运行一遍发现还是有空格,以为我想错了,检查一遍才发现没去掉。

关于语句:mailContent_list[:3000]的作用我不太会,所以搜索了一下:

“从上面2种方法运行时间的对比可以看出,判断1个元素是否在集合中比判断1个元素是否在列表中效率要高。 判断1个元素是否在集合中,使用hash算法,时间复杂度为O(1); 判断1个元素是否在列表中,使用循环遍历对比的方法,时间复杂度为O(n)。 在此次分词结果去除停顿词的实践中,使用判断1个元素是否在集合中的方法,效率是判断1个元素是否在列表中的3倍左右。 64000多篇邮件分词去除停顿词共花费350秒左右,即6分钟左右。”   64000多封邮件我并没有花时间去试。 4.3 保存分词结果

第1行代码导入pickle库第3行代码open方法中的'wb'表示文件以二进制形式写入。第4行代码调用pickle.dump方法将python中的对象保存到文件中。

1 import pickle 2 with open('cutWords_list.pickle', 'wb') as file: 3 pickle.dump(cutWords_list, file) 4.4 加载分词结果

本文作者提供已经完成的分词结果,下载链接: https://pan.baidu.com/s/1bjPgrsXKkovdgbdpzNXOmQ 提取码: x71b 压缩文件cutWords_list.zip下载完成后,其中的文件cutWords_list.pickle解压到代码文件同级目录。

因为之前已经下载过这个文件,并且已经发送到QQ文件助手,所以回到文件助手中去找文件,但是提示文件发送一半,所以我又点了一下接着发送,同时我也在代码运行了

等QQ下载完后,准备复制到目录下,发现已经有了,还是代码运行比较快。

为什么要把分完后的词写入一个文件呢,我猜是分完的词要用到,如果每次用代码现分太麻烦了,所以写入文件后面只调用就可以了。

于37:55开始运行,大概42:50运行完,也差不多六分钟左右,跟博主差不多。

想看一下文件里的内容,于是输出第20000:

import pickle with open('cutWords_list.pickle', 'rb') as file: cutWords_list = pickle.load(file) print(cutWords_list[20000] 但是却发现有一些奇怪的东西出现在里面,这些可以忽略吗,不能忍受,所以我要想办法把它们去掉! 由于列表的下标是从0开始,所以我输出的是第20001封邮件的分词结果,20001/300=60......201 就是data文件夹下059/200,打开之后发现更离谱,跟上面的分词结果更不像,哈哈哈。还不如199打开的内容,因为其实下面的图显示的内容是199文件下的内容:

 通过与分词结果对比发现好像不太一样,不管了。下面加了一个去掉所有非中文字符:

运行结果如下:

 

 没有奇怪的字符了。bingo!

 于是再次写入pickle文件,于11:40运行,17:10结束,差不多6分钟。

运行结果如下:

 

 其实分词这一步我也弄过好多遍了,没什么问题,重要的是下面的。

5.TfidfVectorizer模型

调用sklearn.feature_extraction.text库的TfidfVectorizer方法实例化模型对象。 TfidfVectorizer方法需要3个参数。 第1个参数是分词结果,数据类型为列表,其中的元素也为列表; 第2个关键字参数min_df是词频低于此值则忽略,数据类型为int或float; 第3个关键字参数max_df是词频高于此值则忽略,数据类型为Int或float。 查看TfidfVectorizer方法的更多参数用法,官方文档链接:http://sklearn.apachecn.org/cn/0.19.0/modules/generated/sklearn.feature_extraction.text.TfidfVectorizer.html

1 from sklearn.feature_extraction.text import TfidfVectorizer 2 tfidf = TfidfVectorizer(cutWords_list, min_df=100, max_df=0.25)

我发现文章在刚开始都很认真,但后面就慢慢不认真了。

6.1 特征矩阵

“第1行代码调用TfidfVectorizer对象的fit_transform方法获得特征矩阵; 第2行代码打印查看TfidfVectorizer对象的词表大小; 第3行代码查看特征矩阵的形状。”

1 X = tfidf.fit_transform(mailContent_list) 2 print('词表大小:', len(tfidf.vocabulary_)) 3 print(X.shape)

输出结果为下图:

但是我觉得这个结果好奇怪啊,怎么可能只有44个特征词。于是我去搜了一下tfidf.vocabulary_

博客园中编辑图片想要删除的话,选中之后用delete键删除,backspace键总是跳来跳去,很烦。

我觉得作者对TfidfVectorizer的用法是错误的,正确的应该是上图的样子:

1 # 准备输入的文本数据,我们准备的文本数据是cutWords_list 2 corpus = ['This is the first document.', 3      'This is the second document.', 4      'And this is the third one.', 5      'Is this the first document?',] 6 # 实例化TfidfVectorizer 类 7 vectorizer = TfidfVectorizer() 8 # 将文本数据转化为向量表示 9 X = vectorizer.fit_transform(corpus)

但是我自己生成的cutWords_list中的词格式是['你好','公司',...,]这种,但是方法fit_transform()的参数不能是这种,而是['你好 公司...']这种以空格连接的。那么这种格式怎么做到呢,可以用方法

[' '.join(text) for text in cutWords_list]来做到,即将列表中的元素以空格连接。

 

 加入这样一段话:cutWords_list = [' '.join(text) for text in cutWords_list]

 

根据上面的话,下面的语句就不会出错了:

1 from sklearn.feature_extraction.text import TfidfVectorizer 2 tfidf = TfidfVectorizer(token_pattern=r"(?u)\b\w\w+\b", min_df=100, max_df=0.25) 3 X = tfidf.fit_transform(cutWords_list) 6.2 预测目标值

第1行代码导入sklearn.preprocessing库的LabelEncoder类; 第3行代码调用LabelEncoder()实例化标签编码对象; 第4行代码调用标签编码对象的fit_transform方法获取预测目标值。

1 from sklearn.preprocessing import LabelEncoder 2 labelEncoder = LabelEncoder() 3 y_encode = labelEncoder.fit_transform(y)

看到这个代码觉得有些陌生,这个y我好像并没有见过,但是回去看作者的评论可以发现是有的:

1 with open('./trec06c/full/index') as file: 2 y = [k.split()[0] for k in file.readlines()]

 

这个y_encode的结果就是0,1。

即将A,B,C变成整数0,1,2;那么数字0就表示了类别A。

 

7.逻辑回归模型 7.1 模型训练

最后1行代码ndarray对象的round方法表示小数点保留位数。

1 from sklearn.linear_model import LogisticRegressionCV 2 from sklearn.model_selection import train_test_split 3 train_X, test_X, train_y, test_y = train_test_split(X, y_encode, test_size=0.2) 4 logistic_model = LogisticRegressionCV() 5 logistic_model.fit(train_X, train_y) 6 logistic_model.score(test_X, test_y).round(4)

 

输出结果为0.9917。

到目前为止已经完全做出来了,作者后面还有一些步骤。

7.2 模型保存

保存模型需要先安装pickle库,安装命令:pip install pickle 调用pickle库的dump方法保存模型,需要2个参数。 第1个参数是保存的对象,可以为任意数据类型,因为有3个模型需要保存,所以下面代码第1个参数是字典。 第2个参数是保存的文件对象,数据类型为_io.BufferedWriter

这一步我 没有做,不知道有什么用,所以现在去百度一下啊。 1 import pickle 2 with open('allModel.pickle', 'wb') as file: 3 save = { 4 'labelEncoder' : labelEncoder, 5 'tfidfVectorizer' : tfidf, 6 'logistic_model' : logistic_model 7 } 8 pickle.dump(save, file)

 

 就是将save保存。

也可以保存对象:

1 import pickle 2 with open('allModel.pickle', 'wb') as file: 3 save = { 4 'labelEncoder' : labelEncoder, 5 'tfidfVectorizer' : tfidf, 6 'logistic_model' : logistic_model 7 } 8 pickle.dump(save, file)

pickle我要再了解一下。明显可以看到save是一个字典。

 

 有图中的内容可以了解到存的是对象,可是怎么用呢

 

 发现一个很便利的方法,由于X,y经常用到,所以我也把他们以pickle的方式导出来了。这样我用其他分类算法的时候就不用再搞了,代码如下:

1 with open('X.pickle', 'wb') as file: 2 pickle.dump(X, file) 1 with open('y.pickle', 'wb') as file: 2 pickle.dump(y_encode, file)

测试一下也都是成功的:

 但是我对作者生成的allModel不太满意,想换一下。

因为其中的 'labelEncoder' : labelEncoder,'tfidfVectorizer' : tfidf,这两个我觉得并没有什么要存的必要,只存模型就可以了。

所以接下来我按照自己的想法存了:

1 import pickle 2 with open('LR_Model.pickle', 'wb') as file: 3 pickle.dump(logistic_model,file)

其中logistic_model是一个对象,好像直接这样写并不行,然后我发现作者是写成了字典的样子,所以我也这样写了:

1 import pickle 2 with open('LR_Model.pickle', 'wb') as file: 3 save = {'logistic_model' : logistic_model 4 } 5 pickle.dump(save, file)

这样open就没有问题了。

 

 

 

 在pycharm中试一下能不能成功,试了一下也成功了,但有一些奇奇怪怪的提示。

还有一个问题就是库的版本不一样可能就会出现问题,就像有的程序在别人电脑上能运行到自己电脑上就不行了,所以要注意。

 



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3